package com.example.xd.tuiliu_test.rtp.encode.androidencode;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.util.Log;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * @auther XuDan on 2020/5/14.
 */
public class AAcEncoder {
    private AudioRecord mAudioRecord;
    private Integer mRecordBufferSize;
    private Context context;
    private boolean mWhetherRecord;
    private static final String AUDIO_MIME_TYPE = "audio/mp4a-latm";
    private MediaCodec mEncoder;
    private MediaCodec.BufferInfo mBufferInfo;
    int sampleRate = 44100 * 2;
    int pcmFormat = AudioFormat.CHANNEL_IN_MONO;
    int chanelCount = AudioFormat.ENCODING_PCM_16BIT;


    public AAcEncoder(Context context) {
        initAudioRecord();
        initAudioEncoder(sampleRate, pcmFormat, chanelCount);
        this.context = context;
    }

    /**
     * 初始化编码器
     *
     * @param sampleRate
     * @param pcmFormat
     * @param chanelCount
     */
    private void initAudioEncoder(int sampleRate, int pcmFormat, int chanelCount) {
        MediaFormat audioFormat = MediaFormat.createAudioFormat(AUDIO_MIME_TYPE, sampleRate, chanelCount);
        audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_STEREO);//CHANNEL_IN_STEREO 立体声
        int bitRate = sampleRate * pcmFormat * chanelCount;
        audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
        audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, chanelCount);
        audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
        if (mEncoder != null) {
            return;
        }
        try {
            mEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mEncoder.start();
    }

    /**
     * 初始化音频录制AudioRecord
     * 获取权限
     * 初始化获取每一帧流的Size
     * 初始化音频录制AudioRecord
     * 开始录制与保存录制音频文件
     * 停止录制
     * 给音频文件添加头部信息,并且转换格式成wav
     * 释放AudioRecord,录制流程完毕
     */
    private void initAudioRecord() {
        //获取每一帧的字节流大小
        mRecordBufferSize = AudioRecord.getMinBufferSize(8000
                , AudioFormat.CHANNEL_IN_MONO
                , AudioFormat.ENCODING_PCM_16BIT);
        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC//音频源
                , sampleRate//采样率
                , pcmFormat//声道配置
                , chanelCount//音频格式
                , mRecordBufferSize);//缓存区大小
    }

    /**
     * 开始录制
     */
    public void startRecord() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                record();
            }
        }).start();
    }

    /**
     * 录制流程
     */
    private void record() {
        mWhetherRecord = true;
        mAudioRecord.startRecording();//开始录制
        Log.i("xd----------", "开始录制");
        try {
            byte[] bytes = new byte[mRecordBufferSize];
            while (mWhetherRecord) {
                //读取
                int size = mAudioRecord.read(bytes, 0, bytes.length);
                if (size > 0) {
                    offerEncoder(bytes);
                }
            }
            mAudioRecord.stop();//停止录制
        } catch (Exception e) {
            e.printStackTrace();
            mAudioRecord.stop();
        }
    }

    /**
     * 编码元数据
     *
     * @param bytes
     */
    private void offerEncoder(byte[] bytes) {
        mBufferInfo = new MediaCodec.BufferInfo();
        ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();
        ByteBuffer[] outputBuffers = mEncoder.getOutputBuffers();

        int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(bytes);//添加数据
            mEncoder.queueInputBuffer(inputBufferIndex, 0, bytes.length, System.currentTimeMillis(), 0);
        }
        int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);
        while (outputBufferIndex >= 0) {
            int byteBufSize = mBufferInfo.size;
            int bytePacketSize = byteBufSize + 7;
            ByteBuffer outPutBuf = outputBuffers[outputBufferIndex];
            outPutBuf.position(mBufferInfo.offset);
            outPutBuf.limit(mBufferInfo.offset + mBufferInfo.size);
            byte[] targetByte = new byte[bytePacketSize];
            //添加ADTS头部
            addADTStoPacket(targetByte, bytePacketSize);
            outPutBuf.get(targetByte, 7, byteBufSize);
            outPutBuf.position(mBufferInfo.offset);
            mEncoder.releaseOutputBuffer(outputBufferIndex, false);
            outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);
        }

    }

    /**
     * * 添加ADTS头
     * * @param packet
     * * @param packetLen
     */
    private void addADTStoPacket(byte[] packet, int packetLen) {
        int profile = 2; // AAC LC
        int freqIdx = 4; // 44.1KHz
        int chanCfg = 2; // CPE
        // fill in ADTS data
        packet[0] = (byte) 0xFF;
        packet[1] = (byte) 0xF9;
        packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
        packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }

    /**
     * 停止录制
     */
    public void stopRecord() {
        if (mAudioRecord != null) {
            mAudioRecord.startRecording();
        }
        mWhetherRecord = false;
    }

    public void releaseAudio() {
        if (mAudioRecord != null) {
            mAudioRecord.release();
            mAudioRecord = null;
        }
    }

    public int getAudioState() {
        return mAudioRecord.getState();
    }
}
